using System;
using System.Collections.Generic;
using System.Reflection;

namespace PhillyCodeCamp.Domain.Validation
{
    public class BusinessRuleSet<T> : IBusinessRuleSet where T : IValidation
    {
        private IList<IBusinessRule<T>> rules;

        public BusinessRuleSet(params IBusinessRule<T>[] rules)
            : this(new List<IBusinessRule<T>>(rules))
        {
        }

        public BusinessRuleSet(IList<IBusinessRule<T>> rules)
        {
            this.rules = rules;
        }

        public IBusinessRuleSet BrokenBy(IValidation item)
        {
            IList<IBusinessRule<T>> brokenRules = new List<IBusinessRule<T>>();

            foreach (IBusinessRule<T> rule in rules)
            {
                if (!rule.IsSatisfiedBy((T)item))
                {
                    brokenRules.Add(rule);
                }
            }
            return new BusinessRuleSet<T>(brokenRules);
        }

        public IList<string> Messages
        {
            get
            {
                return new List<IBusinessRule<T>>(rules).ConvertAll<string>(delegate(IBusinessRule<T> rule)
                                                                                {
                                                                                    return rule.Description;
                                                                                });
            }
        }


        public int Count
        {
            get { return rules.Count; }
        }

        public void Add(IBusinessRule<T> rule)
        {
            rules.Add(rule);
        }

        public bool Contains(IRule rule)
        {
            foreach (IBusinessRule<T> businessRule in rules)
            {
                if (rule.Name.Equals(businessRule.Name))
                {
                    return true;
                }
            }
            return false;
        }

        public bool IsEmpty
        {
            get { return Count == 0; }
        }

        public void AddAttributeValidationRules(IValidation domainObject)
        {
            foreach (PropertyInfo property in domainObject.GetType().GetProperties())
            {
                foreach (ValidationAttribute attribute in Attribute.GetCustomAttributes(property, typeof(ValidationAttribute)))
                {
                    attribute.Property = property;
                    rules.Add(new BusinessRule<T>(attribute, domainObject));
                }
            }
        }

        public void AddBrokenRule(IRule brokenRule)
        {
            rules.Add(new BusinessRule<T>(brokenRule.Name, brokenRule.Description, null));
        }
    }
}